#include "resHashMap.h"
#include "Resource.h"
#include "xmlHelper.h"
#include "xmlNodeTree.h"



namespace lpe{
	namespace resman{
		const uint32_t ResourceHashMap::loadResourceFromMetadataFile(const std::string& fileName, Resource* res)
		{
			assertion(res != NULL, "Resource res cannot be NULL");
			XMLHelper xhelper(fileName); // cargar en memoria el fichero xml
			xhelper.init(DEF_APPENDER);
			XMLNodeTree* nt = xhelper.getXMLRootNode(); // obtener el nodo padre para empezarlo a leer

			// busco el ID del recurso, asegurando cada consulta y lanzando una excepcion en caso de error.
			XMLNodeTree* nodeHeader = nt->getChildNodeByName("resourceHeader");
			if(nodeHeader == NULL)
			{
				THROW_AND_LOG(DEF_APPENDER,lpe::core::resourceIncorrectFormatException,"El fichero de recurso no tiene un nodo resourceHeader");
			}
			XMLNodeTree* resourceID = nodeHeader->getChildNodeByName("resourceID");
			if(resourceID == NULL)
			{
				THROW_AND_LOG(DEF_APPENDER,lpe::core::resourceIncorrectFormatException,"El fichero de recurso no tiene un nodo resouceID");
			}
			uint32_t id = resourceID->getNodeValueAsUnsignedInt();

			// Los IDs tienen que ser unicos. Aqui compruebo que no se haya cargado ya.
			if(m_resourceMap.find(id) != m_resourceMap.end())
			{
				m_log->WARNING_MSG(DEF_APPENDER,"Antencion: Este ID [%d] ya existe y el recurso insertado substituye al anterior", id);
			}
			m_log->DEBUG_MSG(DEF_APPENDER,"Cargando recurso con ID %d desde fichero\n\t %s",id,fileName.c_str());
			res->initialize(id,xhelper.getXMLRootNode());
			// insertando el recurso en el hashmap.
			m_resourceMap[id] = new ResourceWithRefCounter(res);
			return id;
		}
		bool ResourceHashMap::isResourceLoaded(const uint32_t id)
		{
			if(m_resourceMap.find(id) == m_resourceMap.end())
				return false;
			return true;
		}
		void ResourceHashMap::init()
		{
			glog::CGlobalLog::initSingleton();
			m_log = &glog::CGlobalLog::getSingleton();
			m_log->addAppender(DEF_APPENDER);
		}

		void ResourceHashMap::releaseResource(const Resource* res)
		{
			releaseResource(res->getID());
		}

		const uint32_t ResourceHashMap::cloneResource(const Resource* start, Resource* end)
		{
			assertion(end != NULL, "Resource res cannot be NULL");
			lpe::core::CUniqueIDXGenerator gen;
			uint32_t id = gen.generate();
			end->clone(*start, id);
			m_resourceMap[id] = new ResourceWithRefCounter(end);
			return id;
		}
		void ResourceHashMap::releaseResource(const uint32_t id)
		{
			m_log->DEBUG_MSG(DEF_APPENDER,"Liberando recurso con ID %d", id);
			// primero decrementamos en uno el item
			uint32_t count = m_resourceMap[id]->decrCount();
			// despues, si ya no hay mas instancias activas y nuestra politica es de borrar siempre, lo borramos definitivamente de la memoria
			if (count == 0 && m_relPolicy == ON_ZERO_COUNT)
			{
				m_log->DEBUG_MSG(DEF_APPENDER,"El recurso con ID %d ya no tiene más instancias y va a ser borrado", id);
				m_resourceMap.erase(id);
			}

		}
		Resource* ResourceHashMap::acquireResource(const uint32_t id)
		{
			if(isResourceLoaded(id))
				return m_resourceMap[id]->getResource();
			return NULL;
		}
		ResourceHashMap::ResourceWithRefCounter::~ResourceWithRefCounter()
		{
			if(m_resource == NULL)
				return;
			delete m_resource;
			m_resource = NULL;
		}
		bool ResourceHashMap::ResourceWithRefCounter::releaseOnZeroCount()
		{
			if(m_refCount > 0)
				return false;
			delete m_resource;
			m_resource = NULL;
			return true;
		}
		ResourceHashMap::ResourceWithRefCounter::ResourceWithRefCounter(Resource* res)
			:m_resource(res)
			,m_refCount(1)
		{}
		const uint32_t ResourceHashMap::ResourceWithRefCounter::incCount()
		{
			++m_refCount;
			return m_refCount;
		}
		const uint32_t ResourceHashMap::ResourceWithRefCounter::decrCount()
		{
			--m_refCount;
			return m_refCount;
		}
	}
}
